#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<ctype.h>

#define IOSIZE 1024
#define DELIM " "
#define NONEREDIR 0
#define INPUTEREDIR 1
#define OUTPUTREDIR 2
#define APPENDREDIR 3

int located;
char cwd[1024];
char environment[1024];
int redir = NONEREDIR;
char* filename = NULL;

const char* getUser()
{
    const char* user = getenv("USER");
    if(user == NULL) return "none";
    return user;
}
const char* getHostname()
{
    const char* hostname = getenv("HOSTNAME");
    if(hostname == NULL) return "none";
    return hostname;
}
const char* getCwd()
{
    const char* pwd = getenv("PWD");
    if(pwd == NULL) return "none";
    return pwd;
}

int iocommand(char* uc,int num)
{

    printf("[%s@%s %s]# ",getUser(),getHostname(),getCwd());
    char* i = fgets(uc,num,stdin);
    if( i == NULL) return -1;
    uc[strlen(uc)-1] = '\0';
    return strlen(uc);
}

void cutcommand(char* uc,char* argv[])
{
    int argc = 0;
    argv[argc++] = strtok(uc,DELIM);
    while(argv[argc++] = strtok(NULL,DELIM));

}

int runcommand(char* argv[])
{
        pid_t id = fork();
        if(id < 0) return -1;
        if(id == 0)
        {
            if(redir == INPUTEREDIR)
            {
                ssize_t fd = open(filename,O_RDONLY);
                dup2(fd,0);
            }
            else if(redir == OUTPUTREDIR)
            {
                ssize_t fd = open(filename,O_WRONLY |O_CREAT |O_TRUNC,0666);
                dup2(fd,1);

            }
            else if(redir == APPENDREDIR)
            {
                ssize_t fd = open(filename,O_WRONLY |O_CREAT |O_APPEND,0666);
                dup2(fd,1);

            }

            execvp(argv[0],argv);
            exit(1);
        }
        else
        {
            int status = 0;
            pid_t rid = waitpid(id,&status,0);
            if(rid >  0)
            {
                located = WEXITSTATUS(status);
            }
        }
        return 0;
}

void cd(char* path)
{
    chdir(path); 
    char newpath[1024];
    getcwd(newpath,sizeof(newpath));
    sprintf(cwd,"PWD=%s",newpath);
    putenv(cwd);
}

void myexport(char* argv[])
{
    strcpy(environment,argv[1]);
    putenv(environment);

}

int myecho(char* argv[])
{
    if(argv[1] == NULL)
    {
        printf("\n");
        return 1;
    }
    if(*(argv[1]) == '$' && strlen(argv[1]) > 1 )
    {
        char* val = argv[1]+1;
        if(strcmp(val,"?") == 0)
        {
            printf("%d\n",located);
            located = 0;
        }
        else
        {
            const char* envl =  getenv(val);
           if(envl) printf("%s\n",envl);
            else printf("\n");
        
        }
        return 1;
    }
    else 
    {
        int argc = 1;
        while(argv[argc])
        {
            printf("%s ",argv[argc]);
            argc++;
        }
        printf("\n");
        return 1;
    }

    return 0;
}

int dobuildin(char* argv[])
{
    if(strcmp(argv[0],"cd") == 0)
    {
        if(argv[1] == NULL) cd(".");
        cd(argv[1]);
        return 1;
    }
    else if(strcmp(argv[0],"export") == 0)
    {
        if(argv[1] == NULL) return 1;
        myexport(argv);
    }
    else if(strcmp(argv[0],"echo") == 0)
    {
        if(argv[1] == NULL)return 1;
       return  myecho(argv);
    }
    return 0;
}

#define SkipSpace(pos) do{while(isspace(*pos)) pos++;}while(0)

void isredir(char uc[],int len)
{
    char* start = uc;
    char* end = &uc[len-1];
    while(end>start)
    {
        if(*end == '>')
        {
           if(*(end-1) == '>')
           {
                *(end-1) = '\0';
                filename = end+1;
                SkipSpace(filename);
                redir = APPENDREDIR;
                break;
           }
           else
           {
               *end = '\0';
               filename = end+1;
               SkipSpace(filename);
                redir = OUTPUTREDIR;
                break;
           }
        }
        else if(*end == '<')
        {
            *end = '\0';
            filename = end+1;
            SkipSpace(filename);
            redir = INPUTEREDIR;
            break;
        }
        else
        {
            end--;
        }
    }

}

int main()
{
    while(1)
    {
        redir = NONEREDIR;
        filename = NULL;
        char usercommand[IOSIZE];
        char* argv[IOSIZE];
        //用户输入和命令行打印
        int i = iocommand(usercommand,sizeof(usercommand));
        if(i <= 0) continue;
        
        //截取之前先判断重定向
        isredir(usercommand,strlen(usercommand));
        //截取指令存储判断内建指令
        cutcommand(usercommand,argv);    
        //内建命令
       int n =  dobuildin(argv);
       if(n) continue;
       //执行
        runcommand(argv);
    }
    return 0;
}






















